home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume10 / lemming / part02 < prev    next >
Encoding:
Text File  |  1987-08-05  |  36.9 KB  |  1,811 lines

  1. Path: uunet!rs
  2. From: rs@uunet.UU.NET (Rich Salz)
  3. Newsgroups: comp.sources.unix
  4. Subject: v10i092:  A graphics editor, Part02/04
  5. Message-ID: <778@uunet.UU.NET>
  6. Date: 6 Aug 87 20:28:10 GMT
  7. Organization: UUNET Communications Services, Arlington, VA
  8. Lines: 1800
  9. Approved: rs@uunet.UU.NET
  10.  
  11. Submitted-by: "Alan W. Paeth" <awpaeth%watcgl.waterloo.edu@RELAY.CS.NET>
  12. Posting-number: Volume 10, Issue 92
  13. Archive-name: lemming/Part02
  14.  
  15. #!/bin/sh
  16. # This is a shell archive, meaning:
  17. # 1. Remove everything above the #!/bin/sh line.
  18. # 2. Save the resulting text in a file.
  19. # 3. Execute the file with /bin/sh (not csh) to create the files:
  20. #    lemmain.c
  21. #    lemmark.c
  22. #    lemmisc.c
  23. #    lemobj.c
  24. #    lemobjsup.c
  25. #    lemop.c
  26. #    lempic.c
  27. #    lemrc.c
  28. #    lemselect.c
  29. #    lemspecial.c
  30. #    lemstart.c
  31. #    lemstop.c
  32. #    lemtext.c
  33. #    lemtick.c
  34. #    lemundo.c
  35. #    lemvec.c
  36. #    lemx.c
  37. # This archive created: Fri Jun 12 18:35:10 1987
  38. # By:    watcgl!awpaethexport PATH; PATH=/bin:$PATH
  39. if test -f 'lemmain.c'
  40. then
  41.     echo shar: over-writing existing file "'lemmain.c'"
  42. fi
  43. cat << \SHAR_EOF > 'lemmain.c'
  44. /*
  45.  * lemmain.c - little editor for mice and other furry rodents (aka lemming)
  46.  *
  47.  * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
  48.  */
  49.  
  50. #include "lem.h"
  51.  
  52. main(argc, argv)
  53.     char **argv;
  54.     {
  55.     int x, y, xup, yup, mup;
  56.     int event, near, drag, dragdist;
  57.     char ch;
  58.  
  59.     startup(argc, argv);
  60.  
  61.     while(1)
  62.     {
  63.     event = getevent(&x, &y, &xup, &yup, &ch);
  64.     if (event != NOEVT) msgclear();
  65.     switch(event)
  66.         {
  67. case NOEVT: idle(); break;
  68. case ALPHA: charadd(line, ch); break;
  69. case CNTRL: switch(ch)
  70.         {
  71.         case C(Q): if (quitconfirm()) break;
  72.         case C(A): all(SELECT, 0); break;
  73.         case C(B): remake(BOX); break;
  74.         case C(C): copysel(); break;
  75.         case C(D): objcompress(); all(DELETE, 0); undo=UNDODEL; break;
  76.         case C(E): remake(ELLI); break;
  77.         case C(F): forceattr(); break;
  78.         case C(G): addgroup(); break;
  79.         case '\177':                     /* <DEL>  */
  80.         case C(H): chardel(line,1); break;        /* <BS>  */
  81.         case C(I): cycleselect(); markdelete(); break;    /* <TAB> */
  82.         case C(J):                    /* <LF>, */
  83.         case C(M): if (markon) stringadd(); break;    /* <CR>  */
  84. /*        case C(K): curveify(); break; */
  85.         case C(L): redraw(); break;
  86.         case C(N): all(DESELECT, 0); break;
  87.         case C(O): writepic(); break;
  88.         case C(P): removegroup(); break;
  89.         case C(R): readfile(); break;
  90.         case C(S): specialfunc(); break;
  91.         case C(T): tickset(); break;
  92.         case C(U): undocmd(); break;
  93.         case C(V): remake(LINE); break;
  94.         case C(W): writefile(); break;
  95.         case C(X): cutlines(); break;
  96.         case C([): all(DESELECT, 0); markdelete(); break; /* <ESC> */
  97.         case C(^): help(); break;            /* ^^ */
  98.         default:   break;
  99.         } break;
  100. case MOUSE: markobj = objnearany(x, y);
  101.         near = markon && (dist(x, y, markx, marky) < MARKTOL);
  102.         dragdist = near ? (anysel ? 0 : MARKTOL) : DRAGTOL;
  103.         drag = dist(x,y,xup,yup) > dragdist;
  104.         if (markobj) objectalign(markobj, &x, &y); else spacealign(&x, &y);
  105.         if (drag)        /* drag stuff */
  106.         {
  107.         if (near)
  108.             {
  109.             markhide();        /* for cleaner update */
  110.             mup = objnearany(xup, yup);
  111.             if (mup && (mup != markobj)) objectalign(mup, &xup, &yup);
  112.             else spacealign(&xup, &yup);
  113.             if (anysel) moveselect(xup-markx, yup-marky);
  114.             else if (markobj) tugunselect(markx, marky, xup, yup);
  115.             markupdate(xup, yup);
  116.             }
  117.         else rectselect(x, y, xup, yup);
  118.         }
  119.         else        /* draw (move mark) cases */
  120.         {
  121.         if (near) markdelete();
  122.         else
  123.             {
  124.             markhide();        /* for cleaner update */
  125.             if (markon && !anysel) lineadd(markx, marky, x, y);
  126.             markupdate(x, y);
  127.             }
  128.         }
  129.         break;
  130.         }
  131.     }
  132.     }
  133. SHAR_EOF
  134. if test -f 'lemmark.c'
  135. then
  136.     echo shar: over-writing existing file "'lemmark.c'"
  137. fi
  138. cat << \SHAR_EOF > 'lemmark.c'
  139. /*
  140.  * lemmark.c - mark control
  141.  *
  142.  * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
  143.  */
  144.  
  145. #include "lem.h"
  146.  
  147. markadd(x, y)
  148.     {
  149.     markdraw(x, y, markobj ? MARKONOBJCOL : MARKONREGCOL);
  150.     markx = x;
  151.     marky = y;
  152.     markon = 1;
  153.     }
  154.  
  155. markdelete()
  156.     {
  157.     markhide();
  158.     markon = 0;
  159.     }
  160.  
  161. markhide()
  162.     {
  163.     if (markon) markdraw(markx, marky, MARKOFFCOL);
  164.     }
  165.  
  166. markupdate(x, y)
  167.     {
  168.     markdelete();
  169.     markobj = objnearany(x, y);
  170.     markadd(x, y);
  171.     }
  172.  
  173. markdraw(x, y, col)
  174.     {
  175.     drawvec(x-MARKSIZE, y, x+MARKSIZE, y, col, 1, EMPHNONE);
  176.     drawvec(x, y-MARKSIZE, x, y+MARKSIZE, col, 1, EMPHNONE);
  177.     }
  178. SHAR_EOF
  179. if test -f 'lemmisc.c'
  180. then
  181.     echo shar: over-writing existing file "'lemmisc.c'"
  182. fi
  183. cat << \SHAR_EOF > 'lemmisc.c'
  184. /*
  185.  * lemmisc.c - low-level routines
  186.  *
  187.  * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
  188.  */
  189.  
  190. #include "lem.h"
  191.  
  192. redraw()
  193.     {
  194.     int i;
  195.     erase();
  196.     if (tickflag) tickdraw();
  197.     forobjects
  198.     {
  199.     objectop(i, UNDEL, UNDEL);
  200.     objectop(i, SEL, SEL);
  201.     }
  202.     if (markon) markadd(markx, marky);
  203.     }
  204.  
  205. idle()
  206.     {
  207.     }
  208. SHAR_EOF
  209. if test -f 'lemobj.c'
  210. then
  211.     echo shar: over-writing existing file "'lemobj.c'"
  212. fi
  213. cat << \SHAR_EOF > 'lemobj.c'
  214. /*
  215.  * lemobj.c - object dispatch
  216.  *
  217.  * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
  218.  */
  219.  
  220. #include "lem.h"
  221.  
  222. objresize(i)
  223.     {
  224.     switch(Otype)
  225.     {
  226.     case LINE: lineresize(i); break;
  227.     case TEXT: textresize(i); break;
  228.     case BOX:  boxresize(i); break;
  229.     case ELLI: elliresize(i); break;
  230.     }
  231.     }
  232.  
  233. objnearpt(i, x, y)
  234.     {
  235.     switch(Otype)
  236.     {
  237.     case LINE: return(linenearpt(i, x, y)); break;
  238.     case TEXT: return(textnearpt(i, x, y)); break;
  239.     case BOX:  return( boxnearpt(i, x, y)); break;
  240.     case ELLI: return(ellinearpt(i, x, y)); break;
  241.     }
  242.     }
  243.  
  244. objinrect(i, xl, yl, xh, yh)
  245.     {
  246.     switch(Otype)
  247.     {
  248.     case TEXT: return(textinrect(i, xl, yl, xh, yh)); break;
  249.     case LINE: return(lineinrect(i, xl, yl, xh, yh)); break;
  250.     case BOX:  return( boxinrect(i, xl, yl, xh, yh)); break;
  251.     case ELLI: return(elliinrect(i, xl, yl, xh, yh)); break;
  252.     }
  253.     }
  254.  
  255. objcantug(i, x, y)
  256.     {
  257.     switch(Otype)
  258.     {
  259.     case TEXT: return(textcantug(i, x, y)); break;
  260.     case LINE: return(linecantug(i, x, y)); break;
  261.     case BOX:  return( boxcantug(i, x, y)); break;
  262.     case ELLI: return(ellicantug(i, x, y)); break;
  263.     }
  264.     }
  265.  
  266. objtug(i, xs, ys, xe, ye)
  267.     {
  268.     switch(Otype)
  269.     {
  270.     case TEXT: texttug(i, xs, ys, xe, ye); break;
  271.     case LINE: linetug(i, xs, ys, xe, ye); break;
  272.     case BOX:   boxtug(i, xs, ys, xe, ye); break;
  273.     case ELLI: ellitug(i, xs, ys, xe, ye); break;
  274.     }
  275.     }
  276.  
  277. objectalign(i, x, y)
  278.     int *x, *y;
  279.     {
  280.     switch(Otype)
  281.     {
  282.     case TEXT: textalign(i, x, y); break;
  283.     case BOX:   boxalign(i, x, y); break;
  284.     case LINE: linealign(i, x, y); break;
  285.     case ELLI: ellialign(i, x, y); break;
  286.     }
  287.     }
  288.  
  289. objmove(i, x, y)
  290.     {
  291.     switch(Otype)
  292.     {
  293.     case LINE: linemove(i, x, y); break;
  294.     case TEXT: textmove(i, x, y); break;
  295.     case BOX:   boxmove(i, x, y); break;
  296.     case ELLI: ellimove(i, x, y); break;
  297.     }
  298.     }
  299.  
  300. objaffine(i, m11, m12, m21, m22)
  301.     float m11, m12, m21, m22;
  302.     {
  303.     switch(Otype)
  304.     {
  305.     case LINE: lineaffine(i, m11, m12, m21, m22); break;
  306.     case TEXT: textaffine(i, m11, m12, m21, m22); break;
  307.     case BOX:   boxaffine(i, m11, m12, m21, m22); break;
  308.     case ELLI: elliaffine(i, m11, m12, m21, m22); break;
  309.     }
  310.     }
  311.  
  312. objdraw(i, col)
  313.     {
  314.     switch(Otype)
  315.     {
  316.     case LINE: linedraw(i, col); break;
  317.     case TEXT: textdraw(i, col); break;
  318.     case BOX:   boxdraw(i, col); break;
  319.     case ELLI: ellidraw(i, col); break;
  320.     }
  321.     }
  322. SHAR_EOF
  323. if test -f 'lemobjsup.c'
  324. then
  325.     echo shar: over-writing existing file "'lemobjsup.c'"
  326. fi
  327. cat << \SHAR_EOF > 'lemobjsup.c'
  328. /*
  329.  * lemobjsup.c - superclass for generic object operations
  330.  *
  331.  * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
  332.  */
  333.  
  334. #include <math.h>        /* to define "double floor()" */
  335. #include "lem.h"
  336.  
  337. objsupnearpt(i, x, y)
  338.     {
  339.     if (ptinrect(x, y, Oxl, Oyl, Oxh, Oyh, LINETOL) == 0) return(0);
  340.     return(1);
  341.     }
  342.  
  343. objsupinrect(i, xl, yl, xh, yh)
  344.     {
  345.     return(ptinrect(Oxl, Oyl, xl, yl, xh, yh, LINETOL) &&
  346.     ptinrect(Oxh, Oyh, xl, yl, xh, yh, LINETOL));
  347.     }
  348.  
  349. objsupcantug(i, x, y)
  350.     {
  351.     return(objnearpt(i, x, y));
  352.     }
  353.  
  354. objsuptug(i, xs, ys, xe, ye)
  355.     {
  356.     if (dist(Oxs, Oys, xs, ys) < TUGPROX) objmove(i, xe-xs, ye-ys);
  357.     }
  358.  
  359. objsupalign(i, x, y)
  360.     int *x, *y;
  361.     {
  362.     if (dist(Oxs, Oys, *x, *y) < ENDTOL)
  363.     {
  364.     *x = Oxs;
  365.     *y = Oys;
  366.     }
  367.     }
  368.  
  369. objsupmove(i, x, y)
  370.     {
  371.     Oxs += x;
  372.     Oxe += x;
  373.     Oys += y;
  374.     Oye += y;
  375.     }
  376.  
  377. objsupaffine(i, m11, m12, m21, m22, both)
  378.     float m11, m12, m21, m22;
  379.     {
  380.     float x1, y1;
  381.     if (both)
  382.     {
  383.     x1 = floor((m11*Oxs + m12*Oys) + 0.5);
  384.         y1 = floor((m21*Oxs + m22*Oys) + 0.5);
  385.     Oxs = x1;
  386.     Oys = y1;
  387.     x1 = floor((m11*Oxe + m12*Oye) + 0.5);
  388.         y1 = floor((m21*Oxe + m22*Oye) + 0.5);
  389.     Oxe = x1;
  390.     Oye = y1;
  391.     }
  392.     else
  393.     {
  394.         x1 = floor((m11*Oxcen + m12*Oycen) + 0.5);
  395.         y1 = floor((m21*Oxcen + m22*Oycen) + 0.5);
  396. /*
  397.  *  move only the center point, don't the other endpoint
  398.  * (presumably object dimensions -- this is a text element).
  399.  */
  400.     objmove(i, (int)(x1-Oxcen), (int)(y1-Oycen));
  401.     }
  402.     }
  403. SHAR_EOF
  404. if test -f 'lemop.c'
  405. then
  406.     echo shar: over-writing existing file "'lemop.c'"
  407. fi
  408. cat << \SHAR_EOF > 'lemop.c'
  409. /*
  410.  * lemop.c - operate on objects (and update the display)
  411.  *
  412.  * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
  413.  */
  414.  
  415. #include "lem.h"
  416.  
  417. objectop(i, instatus, outstatus)
  418.     {
  419.     int col;
  420.     if (i && (Ostat == instatus))
  421.     {
  422.     if ( instatus == SEL) anysel--;
  423.     if (outstatus == SEL) anysel++;
  424.     Ostat = outstatus;
  425.     switch(Ostat)
  426.         {
  427.         case DEL:   col = ERASECOL; break;
  428.         case UNDEL: col = DRAWCOL; break;
  429.         case SEL:   col = SELECTCOL; break;
  430.         }
  431.     objdraw(i, col);
  432.     if (Odel && (i == markobj)) markobj = 0;
  433.     changes |= ( (instatus == DEL) || (outstatus == DEL) );
  434.     if ( instatus == DEL)
  435.     return(1);
  436.     }
  437.     return(0);
  438.     }
  439.  
  440. any(i, opcode)
  441.     {
  442.     if (Ogroup) all(opcode, Ogroup);
  443.     else
  444.     switch(opcode)
  445.     {
  446.     case SELECT:   objectop(i, UNDEL, SEL); break;
  447.     case DESELECT: objectop(i, SEL, UNDEL); break;
  448.     case DELETE:   objectop(i, SEL, DEL);  break;
  449.     case UNDELETE: objectop(i, DEL, SEL);  break;
  450.     }
  451.     }
  452.  
  453. all(opcode, group)
  454.     {
  455.     int i, saveg;
  456.     forobjects
  457.     {
  458.     if (!group || Ogroup == group)
  459.         {
  460.         saveg = Ogroup;
  461.         Ogroup = 0;
  462.         any(i, opcode);
  463.         Ogroup = saveg;
  464.         }
  465.     }
  466.     }
  467. SHAR_EOF
  468. if test -f 'lempic.c'
  469. then
  470.     echo shar: over-writing existing file "'lempic.c'"
  471. fi
  472. cat << \SHAR_EOF > 'lempic.c'
  473. /*
  474.  * lempic.c - PIC output processor
  475.  *
  476.  * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
  477.  */
  478.  
  479. #include "lem.h"
  480.  
  481. #define PTSSCALE 96.0
  482. #define PENSCALE 12    /* ln03 dimp troff drivers like 13 (!a common PntSz) */
  483.  
  484. int curx, cury, curw, curh, ps, pemph;
  485.  
  486. FILE *f;
  487.  
  488. writepicint(fname)
  489.     char *fname;
  490.     {
  491.     int i;
  492.     f = (fname && (strlen(fname) > 1)) ? fopen(fname, "w") : 0;
  493.     if (f)
  494.     {
  495.     curx = cury = curw = curh = ps = pemph= -1;
  496.     fprintf(f, ".PS\n");
  497.     forobjects
  498.         {
  499.         if (Odel) continue;
  500.         switch (Otype)
  501.         {
  502.         case TEXT:    ptext(i);
  503.                 at(Oxs, Oys);
  504.                 break;
  505.         case LINE:    thick(i);
  506.                 pline(i);
  507.                 em(i);
  508.                 from(Oxs, Oys);
  509.                 to(Oxe, Oye);
  510.                 break;
  511.         case BOX:    thick(i);
  512.                 fprintf(f, "box");
  513.                 em(i);
  514.                 at(Ox, Oy);
  515.                 size(Ow, Oh);
  516.                 break;
  517.         case ELLI:    thick(i);
  518.                 fprintf(f, "ellipse");
  519.                 em(i);
  520.                 at(Ox, Oy);
  521.                 size(Ow,Oh);
  522.                 break;
  523.         }
  524.         fprintf(f, ";\n");
  525.         }
  526.     fprintf(f, ".PE\n");
  527.     fclose(f);
  528.     msgpost("pic output done");
  529.     }
  530.     else msgpost("pic output failed");
  531.     free(fname);
  532.     }
  533.  
  534.  
  535. writepic()
  536.     {
  537.     char *fname;
  538.     fname = prompt("pic file: ");
  539.     writepicint(fname);
  540.     free(fname);
  541.     }
  542.  
  543. thick(i)
  544.     {
  545.     if (ps != lemfont[Osizer].thick)
  546.     {
  547.     ps = lemfont[Osizer].thick;
  548.     fprintf(f, ".ps %d\n", ps*PENSCALE);
  549.     }
  550.     }
  551.  
  552. pt(x, y)
  553.     {
  554.     fprintf(f, " %.3fi,%.3fi", (float)(x)/PTSSCALE, (float)(y)/PTSSCALE);
  555.     }
  556.  
  557. at(x, y)
  558.     {
  559.     fprintf(f, " at");
  560.     pt(x, y);
  561.     }
  562.  
  563. from(x, y)
  564.     {
  565.     if ((x == curx) && (y == cury)) return;
  566.     fprintf(f, " from");
  567.     pt(x, y);
  568.     curx = x;
  569.     cury = y;
  570.     }
  571.  
  572. to(x, y)
  573.     {
  574.     fprintf(f, " to");
  575.     pt(x,y);
  576.     curx = x;
  577.     cury = y;
  578.     }
  579.  
  580. size(w, h)
  581.     {
  582.     w = ABS(w);
  583.     h = ABS(h);
  584.     if ((w == curw) && (h == curh)) fprintf(f, " same");
  585.     else
  586.     {
  587.     fprintf(f, " wid %.3fi ht %.3fi",
  588.         (float)(w)/PTSSCALE, (float)(h)/PTSSCALE);
  589.     curw = w;
  590.     curh = h;
  591.     }
  592.     }
  593.  
  594. ptext(i)
  595.     {
  596.     int fontflag;
  597.     char *ft;
  598.     fontflag = ((Oemph != pemph) || (lemfont[Osizer].psize != ps));
  599.     pemph = Oemph;
  600.     ps = lemfont[Osizer].psize;
  601.     fprintf(f, "\"");
  602.     if (fontflag)
  603.     {
  604.     switch(Oemph)
  605.         {
  606.         case EMPHNONE: ft = lemfont[Osizer].tyr; break;
  607.         case EMPHBOLD: ft = lemfont[Osizer].tyb; break;
  608.         case EMPHITAL: ft = lemfont[Osizer].tyi; break;
  609.         }
  610.     fprintf(f, "\\f%s%s", strlen(ft) > 1 ? "(" : "", ft );
  611.     }
  612.     fprintf(f, "\\s%d%s\"",lemfont[Osizer].psize, Otext);
  613.     switch(Oalign)
  614.     {
  615.     case ALIGNLEFT:    fprintf(f, " ljust"); break;
  616.     case ALIGNRGHT:    fprintf(f, " rjust"); break;
  617.     case ALIGNCENT:
  618.     default:    break;
  619.     }
  620.     }
  621.  
  622. pline(i)
  623.     {
  624.     fprintf(f, "line");
  625.     switch(Oalign)
  626.     {
  627.     case ALIGNLEFT: fprintf(f, " <-"); break;
  628.     case ALIGNRGHT: fprintf(f, " ->"); break;
  629.     case ALIGNCENT:
  630.     default:    break;
  631.     }
  632.     }
  633.  
  634. em(i)
  635.     {
  636.     switch(Oemph)
  637.     {
  638.     case EMPHBOLD: fprintf(f, " dashed"); break;
  639.     case EMPHITAL: fprintf(f, " dotted"); break;
  640.     case EMPHNONE:
  641.     default:  break;
  642.     }
  643.     }
  644. SHAR_EOF
  645. if test -f 'lemrc.c'
  646. then
  647.     echo shar: over-writing existing file "'lemrc.c'"
  648. fi
  649. cat << \SHAR_EOF > 'lemrc.c'
  650. /*
  651.  * lemrc.c - get default fonts from local file.
  652.  *
  653.  * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
  654.  */
  655.  
  656. #include "lem.h"
  657. #include "lemfont.h"
  658.  
  659. #define FONTPATH "/usr/local/lib/BFont/"
  660. #define FONTEXTN ".bf"
  661.  
  662. char *getenv();
  663.  
  664. leminit()
  665.     {
  666.     char rcname[100], rcline[RCLINE];
  667.     FILE *f;
  668.     int i, items;
  669. /*
  670.  * generate local and global names
  671.  */
  672.     sprintf(rcname, "./%s", RCNAME);
  673.     f = fopen(rcname, "r");
  674.     if (!f)
  675.     {
  676.         sprintf(rcname, "%s/%s", getenv("HOME"), RCNAME);
  677.     f = fopen(rcname, "r");
  678.     }
  679.     if (!f)
  680.     {
  681. /*    err("no %s file exists", RCGLOBAL); */
  682.     lemfont[1].psize = DEFPSIZEFT;
  683.     lemfont[1].thick = DEFDENSEFT;
  684.     lemfont[1].dsp = DEFIKRFT;
  685.     lemfont[1].tyr = DEFTYRFT;
  686.     lemfont[1].tyb = DEFTYBFT;
  687.     lemfont[1].tyi = DEFTYIFT;
  688.     lemfont[1].psr = DEFPSRFT;
  689.     lemfont[1].psb = DEFPSBFT;
  690.     lemfont[1].psi = DEFPSIFT;
  691.     rclen = 1;
  692.     }
  693.     else
  694.     {
  695.     while(1)
  696.         {
  697.         char dsp[20], tyr[20], tyb[20], tyi[20];
  698.         char psr[20], psb[20], psi[20];
  699.         fgets(rcline, RCLINE, f);
  700.         if (feof(f)) break;
  701.         if ((rcline[0] >= '0') && (rcline[0] <= '9'))
  702.         {
  703.         rclen++;
  704.         if (rclen >= RCLEN) err(".rc file too long");
  705.         items = sscanf(rcline, "%d %d %s %s %s %s %s %s %s",
  706.             &lemfont[rclen].psize, &lemfont[rclen].thick,
  707.             dsp, tyr, tyb, tyi, psr, psb, psi);
  708.         if (items != RCWIDTH) err("wrong line length in .rc file");
  709.         lemfont[rclen].dsp = salloc(dsp);
  710.         lemfont[rclen].tyr = salloc(tyr);
  711.         lemfont[rclen].tyb = salloc(tyb);
  712.         lemfont[rclen].tyi = salloc(tyi);
  713.         lemfont[rclen].psr = salloc(psr);
  714.         lemfont[rclen].psb = salloc(psb);
  715.         lemfont[rclen].psi = salloc(psi);
  716.         }
  717.         }
  718.     if (rclen == 0) err(".lemrc file was empty");
  719.     }
  720.     rclen++;
  721.     if (f) fclose(f);
  722. /*
  723.  * now set up default display fonts
  724.  */
  725.     for (i=1; i<rclen; i++)
  726.     {
  727.     char fontname[100];
  728.     sprintf(fontname, "%s%s%d%s",
  729.         FONTPATH, lemfont[i].dsp, lemfont[i].psize, FONTEXTN);
  730.     bfont[i] = fontload(fontname);
  731.     if (!bfont[i]) err("can't load font \"%s\"", fontname);
  732.     }
  733.     }
  734. SHAR_EOF
  735. if test -f 'lemselect.c'
  736. then
  737.     echo shar: over-writing existing file "'lemselect.c'"
  738. fi
  739. cat << \SHAR_EOF > 'lemselect.c'
  740. /*
  741.  * lemselect.c - object selection and proximity testing
  742.  *
  743.  * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
  744.  */
  745.  
  746. #include "lem.h"
  747.  
  748. cycleselect()
  749.     {
  750.     if (markobj)
  751.     {
  752.     if (objs[markobj]->stat == UNDEL) any(markobj, SELECT);
  753.     else if (objs[markobj]->stat == SEL) any(markobj, DESELECT);
  754.     }
  755.     }
  756.  
  757. rectselect(x0, y0, x1, y1)
  758.     {
  759.     int i, mode, xl, yl, xh, yh;
  760.     xl = MIN(x0, x1);
  761.     yl = MIN(y0, y1);
  762.     xh = MAX(x0, x1);
  763.     yh = MAX(y0, y1);
  764.     mode = (y0 < y1) ? DESELECT : SELECT;
  765.     forobjects
  766.     {
  767.     if (objinrect(i, xl, yl, xh, yh)) any(i, mode);
  768.     }
  769.     }
  770.  
  771. objnearany(x, y)
  772.     {
  773.     int i;
  774.     if (i = objnear(x, y, UNDEL)) return(i);
  775.     return(objnear(x, y, SEL));
  776.     }
  777.  
  778. objnear(x, y, stat)
  779.     {
  780.     int i;
  781.     forobjsrev        /* reverse order search - most recent appears first */
  782.     {
  783.     if (Ostat == stat)
  784.         {
  785.         if (objnearpt(i, x, y)) return(i);
  786.         }
  787.     }
  788.     return(0);
  789.     }
  790. SHAR_EOF
  791. if test -f 'lemspecial.c'
  792. then
  793.     echo shar: over-writing existing file "'lemspecial.c'"
  794. fi
  795. cat << \SHAR_EOF > 'lemspecial.c'
  796. /*
  797.  * lemspecial.c - extra functions for random applications
  798.  *
  799.  * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
  800.  */
  801.  
  802. #include "lem.h"
  803. #include <math.h>
  804.  
  805. specialfunc()
  806.     {
  807.     char ch;
  808.     msgpost("<F>lip <C>cw <M>agnify <R>otate <S>tretch <A>lign: ");
  809.     ch = getstroke();
  810.     switch(UC(ch))
  811.     {
  812.     case 'F': flip(); break;
  813.     case 'C': ccw(); break;
  814.     case 'M': magnify(); break;
  815.     case 'R': rotate(); break;
  816.     case 'S': stretch(); break;
  817.     case 'A': align(); break;
  818.     default: msgpost("unknown transformation"); break;
  819.     }
  820.     }
  821.  
  822. transform(m11, m12, m21, m22)
  823.     float m11, m12, m21, m22;
  824.     {
  825.     int i;
  826. /*
  827.  * record inverse transformation and set undo flag for undoing
  828.  */
  829.     undo = UNDOAFF;
  830.     unx = markx;
  831.     uny = marky;
  832.     un11 = m11;
  833.     un12 = m12;
  834.     un21 = m21;
  835.     un22 = m22;
  836. /*
  837.  * now do the transformations
  838.  */
  839.  forobjects
  840.     {
  841.     if (Osel)
  842.         {
  843.         objectop(i, SEL, DEL);
  844.         objmove(i, -markx, -marky);
  845.         objaffine(i, m11, m12, m21, m22);
  846.         objmove(i,  markx,  marky);
  847.         objresize(i);
  848.         objectop(i, DEL, SEL);
  849.         }
  850.     }
  851.     }
  852.  
  853. flip()
  854.     {
  855.     if (markon)
  856.     {
  857.     transform(-1.0, 0.0, 0.0, 1.0, 1);
  858.     msgpost("flip done");
  859.     }
  860.     else msgpost("flip -- no mark present");
  861.     }
  862.  
  863. ccw()
  864.     {
  865.     if (markon)
  866.     {
  867.     transform(0.0, -1.0, 1.0, 0.0, 0);
  868.     msgpost("ccw turn done");
  869.     }
  870.     else msgpost("ccw -- no mark present");
  871.     }
  872.  
  873. magnify()
  874.     {
  875.     int x1, y1, x2, y2, xs, ys, xe, ye;
  876.     float mag, outlen;
  877.     if (findmark(&x1, &y1, &x2, &y2))
  878.     {
  879.     xs = x2-markx;
  880.     ys = y2-marky;
  881.     xe = x1-markx;
  882.     ye = y1-marky;
  883.     outlen = xs*xs+ys*ys;
  884.     if (outlen != 0.0)
  885.         {
  886.         mag = sqrt((float)(xe*xe+ye*ye)/outlen);
  887.         mag = (mag < 0.1) ? 0.1 : (mag > 10.0 ? 10.0 : mag);
  888.         transform(mag, 0.0, 0.0, mag, 1);
  889.         msgpost("magnify done");
  890.         }
  891.     msgpost("null magnify ignored");
  892.     }
  893.     }
  894.  
  895. stretch()
  896.     {
  897.     int x1, y1, x2, y2, xs, ys, xe, ye;
  898.     float xmag, ymag;
  899.     if (findmark(&x1, &y1, &x2, &y2))
  900.     {
  901.     xs = x2-markx;
  902.     ys = y2-marky;
  903.     xe = x1-markx;
  904.     ye = y1-marky;
  905.     xmag = (xs == 0) ? 1.0 : (float)(xe)/xs;
  906.     ymag = (ys == 0) ? 1.0 : (float)(ye)/ys;
  907.     xmag = (xmag < 0.1) ? 0.1 : (xmag > 10.0 ? 10.0 : xmag);
  908.     ymag = (ymag < 0.1) ? 0.1 : (ymag > 10.0 ? 10.0 : ymag);
  909.     transform(xmag, 0.0, 0.0, ymag, 1);
  910.     msgpost("stretch done");
  911.     }
  912.     }
  913.  
  914. rotate()
  915.     {
  916.     int x1, y1, x2, y2, xs, ys, xe, ye;
  917.     float s, c, hy;
  918.     if (findmark(&x1, &y1, &x2, &y2))
  919.     {
  920.     xs = x2-markx;
  921.     ys = y2-marky;
  922.     xe = x1-markx;
  923.     ye = y1-marky;
  924.     hy = sqrt((float)( (xs*xs + ys*ys) * (xe*xe + ye*ye) ));
  925.     if (hy != 0.0)
  926.         {
  927.         c =  (xs*xe+ys*ye)/hy;
  928.         s =  (xs*ye-xe*ys)/hy;
  929.         transform(c, -s, s, c, 0);
  930.         msgpost("rotate done");
  931.         }
  932.     else msgpost("null rotation ignored");
  933.     }
  934.     }
  935.  
  936. align()
  937.     {
  938.     int x1, y1, x2, y2, xs, ys, xe, ye, scale;
  939.     float m11, m12, m21, m22, det;
  940.     if (findmark(&x1, &y1, &x2, &y2))
  941.     {
  942.     xs = x2-markx;
  943.     ys = y2-marky;
  944.     xe = x1-markx;
  945.     ye = y1-marky;
  946.     scale = MAX(MAX(ABS(xs),ABS(ys)),MAX(ABS(xe),ABS(ye)));
  947.     det = xe*ys - xs*ye; 
  948.     m11 = (float)( ys*scale)/det;
  949.     m12 = (float)(-xs*scale)/det;
  950.     m21 = (float)(-ye*scale)/det;
  951.     m22 = (float)( xe*scale)/det;
  952.     transform(m11, m12, m21, m22, 1);
  953.     msgpost("align done");
  954.     }
  955.     }
  956.     
  957. findmark(x1, y1, x2, y2)
  958.     int *x1, *y1, *x2, *y2;
  959.     {
  960.     int i, s, e, arrow, straight;
  961.     arrow = straight = 0;
  962.     if (!markon)
  963.     {
  964.     msgpost("transform: no mark present");
  965.     return(0);
  966.     }
  967.     else
  968.     {
  969.     forobjects
  970.         {
  971.         if (Otype != LINE) continue;
  972.         s = (Oxs == markx) && (Oys == marky);
  973.         e = (Oxe == markx) && (Oye == marky);
  974.         if (s || e) 
  975.         {
  976.         switch (Oalign)
  977.             {
  978. case ALIGNCENT:        *x1 = s ? Oxe : Oxs;
  979.             *y1 = s ? Oye : Oys;
  980.             straight++;
  981.             break;
  982. case ALIGNLEFT:        if (s)
  983.             {
  984.             msgpost("transform: arrowhead at origin");
  985.             return(0);
  986.             }
  987.             *x2 = Oxs;
  988.             *y2 = Oys;
  989.             arrow++;
  990.             break;
  991. case ALIGNRGHT:        if (e)
  992.             {
  993.             msgpost("transform: arrowhead at origin");
  994.             return(0);
  995.             }
  996.             *x2 = Oxe;
  997.             *y2 = Oye;
  998.             arrow++;
  999.             break;
  1000.             }
  1001.         }
  1002.         }
  1003.     }
  1004.     if ((arrow == 1) && (straight == 1)) return(1);
  1005. /*
  1006.  * errors 
  1007.  */
  1008.     if (arrow+straight == 0)
  1009.     msgpost("transform: no basis vectors at mark");
  1010.     else if (arrow != 1)
  1011.     msgpost("transform: exactly one arrow basis vector needed");
  1012.     else if (straight != 1)
  1013.     msgpost("transform: exactly one non-arrow basis vector needed");
  1014.     return(0);
  1015.     }
  1016. SHAR_EOF
  1017. if test -f 'lemstart.c'
  1018. then
  1019.     echo shar: over-writing existing file "'lemstart.c'"
  1020. fi
  1021. cat << \SHAR_EOF > 'lemstart.c'
  1022. /*
  1023.  * lemstart.c - check command line, plus some housecleaning
  1024.  *
  1025.  * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
  1026.  */
  1027.  
  1028. #include "lem.h"
  1029.  
  1030. startup(argc, argv)
  1031.     char **argv;
  1032.     {
  1033.     int i, plotmode;
  1034.     plotmode = 0;
  1035. /*
  1036.  * initialize based on probable .rc file
  1037.  */
  1038.     leminit();
  1039. /*
  1040.  * set up object defaults
  1041.  */
  1042.     lastobj = 1;        /* no objects */
  1043.     setattr('0');        /* default attr's (as if '0' typed) */
  1044.     gtype = LINE;        /* draw lines by default */
  1045.     undo = UNDONONE;        /* no operation to undo */
  1046. /*
  1047.  * start user code and refresh the display
  1048.  */
  1049.     start();    
  1050.     redraw();
  1051. /*
  1052.  * command line prompt
  1053.  */
  1054.     msgpost("lemming ver 1 -- 'ctrl ^' for help");
  1055. /*
  1056.  * possible file name on cmd line
  1057.  */
  1058.     changes = 0;    /* no changes at present */
  1059. /*
  1060.  * do all command line parsing
  1061.  */
  1062.     for(i=1; i<argc; i++)
  1063.         {
  1064.     if (argv[i][0] == '-')
  1065.         {
  1066.         switch(argv[i][1])
  1067.         {
  1068.         case 'p':
  1069.         case 'P': plotmode = 1; break;
  1070.         default: err("unknown command line flag"); break;
  1071.         }
  1072.         }
  1073.     else
  1074.         {
  1075.         if (!firstfile) firstfile = argv[i]; /* record first input file */
  1076.         readfileint(argv[i]);
  1077.         }
  1078.     }
  1079.     if (plotmode)
  1080.     {
  1081.     char outname[80];
  1082.     sprintf(outname, "%s.pic", firstfile);
  1083.     writepicint(outname);
  1084.     stop();
  1085.     exit(0);
  1086.     }
  1087.     }
  1088. SHAR_EOF
  1089. if test -f 'lemstop.c'
  1090. then
  1091.     echo shar: over-writing existing file "'lemstop.c'"
  1092. fi
  1093. cat << \SHAR_EOF > 'lemstop.c'
  1094. /*
  1095.  * lemstop.c - quit and error returns from lemming.
  1096.  *
  1097.  * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
  1098.  */
  1099.  
  1100. #include "lem.h"
  1101.  
  1102. quitconfirm()
  1103.     {
  1104.     char c;
  1105.     if (changes)
  1106.     {
  1107.     msgpost("quit: [y] to confirm: ");
  1108.     c = getstroke();
  1109.     if (UC(c) != 'Y')
  1110.         {
  1111.         msgpost("quit aborted.");
  1112.         return(1);
  1113.         }
  1114.     }
  1115.     markdelete();
  1116.     stop();
  1117.     exit(0);
  1118.     }
  1119.  
  1120. err(msg, arg)
  1121.     char *msg;
  1122.     {
  1123.     fprintf(stderr, "\nlem: ", msg, arg);
  1124.     fprintf(stderr, msg, arg);
  1125.     fprintf(stderr, "\n");
  1126.     exit(1);
  1127.     }
  1128. SHAR_EOF
  1129. if test -f 'lemtext.c'
  1130. then
  1131.     echo shar: over-writing existing file "'lemtext.c'"
  1132. fi
  1133. cat << \SHAR_EOF > 'lemtext.c'
  1134. /*
  1135.  * lemtext.c - text primitives
  1136.  *
  1137.  * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
  1138.  */
  1139.  
  1140. #include "lem.h"
  1141. #include "lemfont.h"
  1142.  
  1143. textadd(x0, y0, s)
  1144.     char *s;
  1145.     {
  1146.     int i;
  1147.     if ((!s) || (strlen(s) == 0)) return;
  1148.     i = objalloc(TEXT);
  1149.     Otext = salloc(s);
  1150.     Oxs = x0;
  1151.     Oys = y0;
  1152.     textresize(i);
  1153.     objnew(i);
  1154.     }
  1155.  
  1156. textresize(i)
  1157.     {
  1158.     Oxe = fontmeasure(bfont[Osizer], Otext, Oemph);
  1159.     Oye = lemfont[Osizer].psize;
  1160.     }
  1161.  
  1162. textnearpt(i, x, y)
  1163.     {
  1164.     return(ptinrect(x, y, Oxlt, Oylt, Oxht, Oyht, TEXTTOL));    /* must be ON the text */
  1165.     }
  1166.  
  1167. textinrect(i, xl, yl, xh, yh)
  1168.     {
  1169.     return(ptinrect(Oxlt, Oylt, xl, yl, xh, yh, TEXTTOL) &&
  1170.     ptinrect(Oxht, Oyht, xl, yl, xh, yh, TEXTTOL) );
  1171.     }
  1172.  
  1173. textcantug(i, x, y)
  1174.     {
  1175.     return(textnearpt(i, x, y));
  1176.     }
  1177.  
  1178. texttug(i, xs, ys, xe, ye)
  1179.     {
  1180.     Oxs += xe-xs;
  1181.     Oys += ye-ys;
  1182.     }
  1183.  
  1184. textalign(i, x, y)
  1185.     int *x, *y;
  1186.     {
  1187.     *x = Oxs;
  1188.     *y = Oys;
  1189.     }
  1190.  
  1191. textmove(i, x, y)
  1192.     {
  1193.     Oxs += x;
  1194.     Oys += y;
  1195.     }
  1196.  
  1197. textaffine(i, m11, m12, m21, m22)
  1198.     float m11, m12, m21, m22;
  1199.     {
  1200.     objsupaffine(i, m11, m12, m21, m22, 0);
  1201.     }
  1202.  
  1203. textdraw(i, col)
  1204.     {
  1205.     fontwrite(Osizer, Oxlt, Oys, Otext, Oemph, col);
  1206.     }
  1207. SHAR_EOF
  1208. if test -f 'lemtick.c'
  1209. then
  1210.     echo shar: over-writing existing file "'lemtick.c'"
  1211. fi
  1212. cat << \SHAR_EOF > 'lemtick.c'
  1213. /*
  1214.  * lemtick.c - perform ticking
  1215.  *
  1216.  * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
  1217.  */
  1218.  
  1219. #include "lem.h"
  1220. #include "lemfont.h"
  1221.  
  1222. tickalign(x, y)
  1223.     int *x, *y;
  1224.     {
  1225.     if (tickflag && (ticksize < 6))
  1226.     {
  1227.     tx = 1<<ticksize;
  1228.     ty = 1<<ticksize;
  1229.     *x = ((*x-txoff+tx/2) / tx) * tx + txoff;
  1230.         *y = ((*y-tyoff+ty/2) / ty) * ty + tyoff;
  1231.     }
  1232.     if (tickflag && (ticksize >= 6))
  1233.     {
  1234.     int xl, yi, yl, d1, d2, d3, d4;
  1235.     tx = 1<<(ticksize-3);
  1236.     ty = (tx*14+7)/16;
  1237.         yi = ((*y-tyoff)/ty);
  1238.         yl = yi*ty + tyoff;
  1239.     xl = (((*x-txoff+((yi&0x1)?tx/2:0))/tx)*tx-((yi&0x1)?tx/2:0))+txoff;
  1240.     
  1241.     d1 = dist(*x,*y,xl       ,yl);
  1242.     d2 = dist(*x,*y,xl+tx/2  ,yl+ty);
  1243.     d3 = dist(*x,*y,xl+tx    ,yl);
  1244.     d4 = dist(*x,*y,xl+3*tx/2,yl+ty);
  1245.     if ((d1<=d2) && (d1<=d3) && (d1<=d4)) { *x = xl;        *y = yl; }
  1246.     if ((d2<=d1) && (d2<=d3) && (d2<=d4)) { *x = xl+tx/2;   *y = yl+ty; }
  1247.     if ((d3<=d1) && (d3<=d2) && (d3<=d4)) { *x = xl+tx;     *y = yl; }
  1248.     if ((d4<=d1) && (d4<=d2) && (d4<=d3)) { *x = xl+3*tx/2; *y = yl+ty; }
  1249.     }
  1250.     }
  1251.  
  1252. tickset()
  1253.     {
  1254.     char ch;
  1255.     int tmpx, tmpy;
  1256.     tickflag = !tickflag;
  1257.     if (tickflag)
  1258.     {
  1259.     msgpost("ticksize[1-5/6-9]: ");
  1260.     ch = getstroke();
  1261.     msgclear();
  1262.     if ((ch < '0') || (ch > '9'))
  1263.         {
  1264.         tickflag = 0;
  1265.         return;
  1266.         }
  1267.     ticksize = ch - '0';
  1268.     tmpx = markon ? markx : 0;
  1269.     tmpy = markon ? marky : 0;
  1270.         txoff = 0;
  1271.         tyoff = 0;
  1272.     tickalign(&tmpx, &tmpy);    /* sets tx and ty as well */
  1273.     txoff = (markon ? markx : 0) - tmpx;
  1274.     tyoff = (markon ? marky : 0) - tmpy;
  1275.     while (tyoff > 0) tyoff -= ty;
  1276.     while (tyoff < 0) tyoff += ty;
  1277.     while (txoff > 0) txoff -= tx;
  1278.     while (txoff < 0) txoff += tx;
  1279.     }
  1280.     tickdraw();
  1281.     if (!tickflag)
  1282.     {
  1283.         txoff = 0;
  1284.         tyoff = 0;
  1285.     }
  1286.     }
  1287.     
  1288. tickdraw()
  1289.     {
  1290.     int x, y, xstep, ystep;
  1291.     xstep = tx;
  1292.     ystep = ty;
  1293.     while (xstep<MINTICK) xstep *= 2;
  1294.     while (ystep<MINTICK) ystep *= 2;
  1295.     if (ticksize < 6)
  1296.     {
  1297.     for(y = tyoff ; y<screenh; y+=ystep)
  1298.         for (x = txoff; x<screenw; x+=xstep)
  1299.             {
  1300.         drawvec(x, y, x + tickdot, y, tickflag ? TICKONCOL:TICKOFFCOL,
  1301.             1,EMPHNONE); /* tickdot sets 0/1 width dot */
  1302.         }
  1303.     }
  1304.     else
  1305.         {
  1306.     int ylim, iy;
  1307.     ylim = screenh/ty;
  1308.     y = tyoff;
  1309.     for(iy=0; iy<ylim; iy++)
  1310.         {
  1311.         y += ty;
  1312.         for (x = txoff + ((iy&0x1) ? 0 : (tx/2)); x<screenw; x+=tx)
  1313.         if ((x>0) && (y>0))
  1314.                 drawvec(x, y, x + tickdot, y,
  1315.             tickflag ? TICKONCOL:TICKOFFCOL,1,EMPHNONE);
  1316.         }
  1317.     }
  1318.     }
  1319. SHAR_EOF
  1320. if test -f 'lemundo.c'
  1321. then
  1322.     echo shar: over-writing existing file "'lemundo.c'"
  1323. fi
  1324. cat << \SHAR_EOF > 'lemundo.c'
  1325. /*
  1326.  * lemundo.c - undo last operation
  1327.  *
  1328.  * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
  1329.  */
  1330.  
  1331. #include "lem.h"
  1332.  
  1333. undocmd()
  1334.     {
  1335.     float d;
  1336.     switch(undo)
  1337.     {
  1338. case UNDOMOVE:    moveselect(-unx, -uny);
  1339.         break;
  1340. case UNDOTUG:    tugunselect(unxe, unye, unx, uny);
  1341.         break;
  1342. case UNDOAFF:    d = (un11 * un22) - (un21 * un12);
  1343.             if (d == 0.0) return;    /* no-op if singular */
  1344.             transform(un22/d, -un12/d, -un21/d, un11/d);
  1345.         break;
  1346. case UNDODEL:    all(UNDELETE, 0);
  1347.         undo = UNDONONE;
  1348.         break;
  1349. default:    undo = UNDONONE;
  1350. case UNDONONE:    msgpost("cannot undo last operation"); break;
  1351.     }
  1352.     }
  1353. SHAR_EOF
  1354. if test -f 'lemvec.c'
  1355. then
  1356.     echo shar: over-writing existing file "'lemvec.c'"
  1357. fi
  1358. cat << \SHAR_EOF > 'lemvec.c'
  1359. /*
  1360.  * lemvec.c - line to point scan conversion
  1361.  *
  1362.  * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
  1363.  */
  1364.  
  1365. /*
  1366.  *
  1367.  * Programmed by Alan Paeth, University of Waterloo, January, 1984
  1368.  *
  1369.  * This code rasterizes vectors. A call of the form:
  1370.  *
  1371.  * drawline(x0, y0, x1, y1, wid, val, emph)
  1372.  *
  1373.  * with val the output color, and emph one of EMPHITAL, EMPHBOLD, (otherwise)
  1374.  * generates a vector of specified which is dotted, dashed, or plain,
  1375.  * respectively.
  1376.  *
  1377.  * output pixels are set by calls to:
  1378.  *
  1379.  * setpixelrun(x, y, wid, val, parity)
  1380.  *
  1381.  * which should set pixels (x,y) through (x+wid-1,y) to color (val) if
  1382.  * parity is 0 (as it is at endpoints and some intermediate locations).
  1383.  *
  1384.  * viewport clipping is done (using integer math) to the dimensions specified
  1385.  * in the globals "screenw" and "screenh"
  1386.  *
  1387.  */
  1388.  
  1389. #include "lem.h"
  1390.  
  1391. #define Nextflag { mask>>=1; if (++flag >= 16) { flag = 0; mask = emph; } }
  1392.  
  1393. #define SOLID  0xffffffff    /* only solid should have sign bit set */
  1394. #define DASHES 0x00ff00ff
  1395. #define DOTS   0x03030303
  1396.  
  1397. #define ONE        0x4000
  1398. #define POINT_FIVE    0x2000
  1399. #define SCALEUP    14
  1400.  
  1401. #define TOPFLAG 8
  1402. #define BOTTOMFLAG 4
  1403. #define LEFTFLAG 2
  1404. #define RIGHTFLAG 1
  1405.  
  1406. code(x, y)
  1407.     float x, y;
  1408.     {
  1409.     int c = 0;
  1410.     if (x < 0) c |= LEFTFLAG; else if (x >= screenw) c |= RIGHTFLAG;
  1411.     if (y < 0) c |= BOTTOMFLAG; else if (y >= screenh) c |= TOPFLAG;
  1412.     return c;
  1413.     }
  1414.  
  1415. drawline(x1, y1, x2, y2, wid, val, emph) /* generic brand clipped line code */
  1416.     {
  1417.     int c, c1, c2;
  1418.     long x, y;
  1419.  
  1420.     if ((x1==x2) && (y1==y2)) return;    /* no motion -- fast return */
  1421.  
  1422.     c1 = code((float)(x1), (float)(y1));
  1423.     c2 = code((float)(x2), (float)(y2));
  1424.  
  1425.     while (c1 || c2)
  1426.     {
  1427.     if (c1 & c2) return;    /* bitwise AND, not statement AND */
  1428.     c = c1 ? c1 : c2;
  1429.     
  1430.     if (c & LEFTFLAG)
  1431.         y = y1 + ((y2 - y1) * ( (x = 0) - x1)) / (x2 - x1);
  1432.     else if (c & RIGHTFLAG)
  1433.         y = y1 + ((y2 - y1) * ( (x = screenw) - x1)) / (x2 - x1);
  1434.     else if (c & TOPFLAG)    
  1435.         x = x1 + ((x2 - x1) * ( (y = screenh) - y1)) / (y2 - y1);
  1436.     else if (c & BOTTOMFLAG)    
  1437.         x = x1 + ((x2 - x1) * ( (y = 0) - y1)) / (y2 - y1);
  1438.     
  1439.     if (c == c1)
  1440.         {
  1441.         x1 = x;
  1442.         y1 = y;
  1443.         c1 = code(x, y);
  1444.         }
  1445.     else
  1446.         {
  1447.         x2 = x;
  1448.         y2 = y;
  1449.         c2 = code(x, y);
  1450.         }
  1451.     }
  1452.     fastdrawline(x1, y1, x2, y2, wid, val, emph);
  1453.     }
  1454.  
  1455. fastdrawline(x1, y1, x2, y2, wid, val, emph)
  1456.  
  1457. /*
  1458.  *
  1459.  *  Draws a line of pixels=val from (x1, y1) to (x2, y2) very fast.
  1460.  *
  1461.  *  This is algorithm A1 from "Filtering Edges for Grey-Scale Displays" by
  1462.  *  Gupta & Sproull (Computer Graphics 15,3 August 1981). No anti-aliasing
  1463.  *  is being done here. However the variable 'v' can be *  used to turn on
  1464.  *  pixels to the left and right (above and below) the line since v is
  1465.  *  horizontal distance from the center of the line to the pixel at (x, y).
  1466.  *
  1467.  *  Last Hacked by: Alan Paeth
  1468.  */
  1469.  
  1470.     int x1, y1, x2, y2, val, emph;
  1471.     {
  1472.     register    x, y;            /* current position in line */
  1473.     int        incr;            /* y increment = + or - 1 */
  1474.     int        dx, dy;            /* change in x, y */
  1475.     int        m;            /* slope of line ( * 2 ** 14 ) */
  1476.     int        s;            /* threshold for diagonal move */
  1477.     register    v;            /* dist from line to pixel */
  1478.     int        mm1;            /* m - (1 << 9) */
  1479.     int        mask;
  1480.     int        flag;
  1481.  
  1482.     flag = 0;
  1483.     emph = (emph == EMPHITAL) ? DOTS : ((emph == EMPHBOLD) ? DASHES : SOLID);
  1484.     mask = emph;
  1485.  
  1486.     if (y2 > y1)            /* make y1 > y2 by symmetries */
  1487.     {
  1488.     x = x1;   x1 = x2;   x2 = x;
  1489.     y = y1;   y1 = y2;   y2 = y;
  1490.     }
  1491.  
  1492.     incr = 1;
  1493.     dy   = y1 - y2;
  1494.  
  1495.     if ((dx = x2 - x1) < 0)
  1496.     {
  1497.     dx   = -dx;
  1498.     incr = -1;
  1499.     }
  1500.  
  1501.     v = 0;
  1502.     if (dx > dy)
  1503.     {
  1504.     m = ((long)dy << SCALEUP) / (long)dx;
  1505.     s = POINT_FIVE - m;
  1506.     mm1 = m - ONE;
  1507.     y = y1;
  1508.  
  1509.     for( x = x1; x != x2; x += incr )
  1510.         {
  1511.         if (mask & 0x1) setpixelrunv(x, y, wid, val, flag & 0x1);
  1512.         Nextflag;
  1513.         if( v >= s ) { --y; v += mm1; }    /* diagonal move */
  1514.         else v += m;            /* horizontal move */
  1515.         }
  1516.     setpixelrunv(x, y, wid, val, 0);
  1517.     }
  1518.     else
  1519.     {
  1520.     if( dy > 0 )
  1521.         {
  1522.         m = ((long)dx << SCALEUP) / (long)dy;
  1523.         s = POINT_FIVE - m;
  1524.         mm1 = m - ONE;
  1525.         }
  1526.     x = x1;
  1527.  
  1528.     for( y = y1; y > y2; --y )
  1529.         {
  1530.         if (mask & 0x1) setpixelrunh(x, y, wid, val, flag&0x1);
  1531.         Nextflag;
  1532.         if ( v >= s ) { x += incr; v += mm1; }    /* diagonal move */
  1533.         else v += m;                /* vertical move */
  1534.         }
  1535.     setpixelrunh(x, y, wid, val, 0);
  1536.     }
  1537.     }
  1538. SHAR_EOF
  1539. if test -f 'lemx.c'
  1540. then
  1541.     echo shar: over-writing existing file "'lemx.c'"
  1542. fi
  1543. cat << \SHAR_EOF > 'lemx.c'
  1544. /*
  1545.  * lemx.c - lemming driver for X window software
  1546.  *
  1547.  * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
  1548.  */
  1549.  
  1550. #include "lem.h"
  1551. #include <X/Xlib.h>
  1552.  
  1553. #define EV (ButtonPressed | ButtonReleased | KeyPressed | ExposeWindow | ExposeRegion)
  1554.  
  1555. Window win;
  1556. int xsave, ysave, drawcol, erasecol, selectcol, markoncol, markoffcol, lut;
  1557. int sysmsgloc;
  1558. char sysmsg[120];
  1559. unsigned char maptab[256];    /* bit reversing table */
  1560.  
  1561. start()
  1562.     {
  1563.     screenw = 512;
  1564.     screenh = 512;
  1565.     if ((XOpenDisplay("")) == NULL) err("display open failed");
  1566.     win = XCreateWindow(RootWindow, screenw/2, screenh/2, screenw, screenh,
  1567.                 2, WhitePixmap, BlackPixmap);
  1568.     if (win == NULL) err("window open failed");
  1569.     lut = DisplayCells() > 2;
  1570.     XMapWindow(win);
  1571.     XSelectInput(win, EV);
  1572.     if (lut)
  1573.     {
  1574.     cblack = findcolor(0,0,0);
  1575.     cwhite = findcolor(1,1,1);
  1576.     cred   = findcolor(1,0,0);
  1577.     cgreen = findcolor(0,1,0);
  1578.     tickdot = 0;
  1579.     }
  1580.     else
  1581.     {
  1582.     cwhite = 1;
  1583.     cblack = 0;
  1584.     cred   = 2;
  1585.     cgreen = 1;
  1586.     tickdot = 1;
  1587.     }
  1588.     setcursor();
  1589.     }
  1590.  
  1591. stop()
  1592.     {
  1593.     }
  1594.  
  1595. getevent(xdn, ydn, xup, yup, ch)
  1596.     int *xdn, *ydn, *xup, *yup;
  1597.     char *ch;
  1598.     {
  1599.     int ret, count;
  1600.     XEvent ev;
  1601.     XWindowEvent(win, EV, &ev);
  1602.     ret = NOEVT;
  1603.     switch(ev.type)
  1604.     {
  1605.     case ButtonPressed:    xsave = mx(&ev);
  1606.                 ysave = my(&ev);
  1607.                 break;
  1608.     case ButtonReleased:    *xdn = xsave;
  1609.                 *ydn = ysave;
  1610.                 *xup = mx(&ev);
  1611.                 *yup = my(&ev);
  1612.                 ret = MOUSE;
  1613.                 break;
  1614.     case KeyPressed:    *ch = *XLookupMapping(&ev, &count);
  1615.                 if (*ch)
  1616.                    {
  1617.                    if ((*ch >= ' ') && (*ch != '\177'))
  1618.                        ret = ALPHA;
  1619.                    else if (*ch > 0) ret = CNTRL;
  1620.                    }     
  1621.                 break;
  1622.     case ExposeRegion:
  1623.     case ExposeWindow:    checkwindowsize();
  1624.                 redraw();
  1625.                 break;
  1626.     }
  1627.     XFlush();
  1628.     return(ret);
  1629.     }
  1630.  
  1631. checkwindowsize()
  1632.     {
  1633.     WindowInfo winfo;
  1634.     XQueryWindow(win, &winfo);
  1635.     screenw = winfo.width;
  1636.     screenh = winfo.height;
  1637.     }
  1638.  
  1639. setcursor()
  1640.     {
  1641.     Cursor c;
  1642.     static short cur_bgnd[] = {
  1643.     0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x03e0, 0x0630, 0x7c1f, 0x7c1f,
  1644.     0x7c1f, 0x0630, 0x03e0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x0000 };
  1645.     static short cur_fgnd[] = {
  1646.     0x0080, 0x0080, 0x0080, 0x0080, 0x03e0, 0x0630, 0x0410, 0x7c1f,
  1647.     0x0410, 0x0630, 0x03e0, 0x0080, 0x0080, 0x0080, 0x0080, 0x0000 };
  1648.     c = XCreateCursor(16, 16, cur_fgnd, cur_bgnd, 7,7,cwhite,cblack,GXcopy);
  1649.     XDefineCursor(win, c);
  1650.     }
  1651.  
  1652. setpixelrunh(x0, y0, wid, col, dotflag)
  1653.     {
  1654.     if (col == cred)
  1655.     {
  1656.     col = (dotflag) ? cblack: cwhite;    /* checkerboard select */
  1657.     }
  1658.     XPixSet(win, x0, (screenh-1)-y0, wid, 1, col);
  1659.     }
  1660.  
  1661. setpixelrunv(x0, y0, wid, col, dotflag)
  1662.     {
  1663.     if (col == cred)
  1664.     {
  1665.     col = (dotflag) ? cblack: cwhite;    /* checkerboard select */
  1666.     }
  1667.     XPixSet(win, x0, (screenh-1)-y0, 1, wid, col);
  1668.     }
  1669.  
  1670. drawvec(x0, y0, x1, y1, col, wid, emph)
  1671.     {
  1672. #define SOLID  SolidLine
  1673. #define DASHES XMakePattern(0x00ff,16,1)
  1674. #define DOTS   XMakePattern(0x0303,16,1)
  1675.     Vertex chain[2];
  1676.     int pattern;
  1677.     if (lut)
  1678.     {
  1679. /*    XLine(win,x0,screenh-y0,x1,screenh-y1,wid,wid,col,GXcopy,AllPlanes); */
  1680.     chain[0].x = x0 - wid/2;
  1681.     chain[0].y = screenh-y0 - wid/2;
  1682.     chain[0].flags = VertexDrawLastPoint;
  1683.     chain[1].x = x1 - wid/2;
  1684.     chain[1].y = screenh-y1 - wid/2;
  1685.     chain[1].flags = VertexDrawLastPoint;
  1686.     pattern = (emph==EMPHNONE) ? SOLID : ((emph==EMPHBOLD) ? DASHES : DOTS);
  1687.     XDrawDashed(win, chain, 2, wid, wid, col, pattern, GXcopy, AllPlanes);
  1688.     }
  1689.     else drawline(x0-wid/2, y0+wid/2, x1-wid/2, y1+wid/2, wid, col, emph);
  1690. /* SUN version does not understand dots and dashes -- we must do it all */
  1691.     }
  1692.  
  1693. charshow(str)
  1694.     char *str;
  1695.     {
  1696.     int i;
  1697.     for(i=0; i<strlen(str); i++) sysmsg[sysmsgloc++] = str[i];
  1698.     sysmsg[sysmsgloc] = '\0';
  1699.     fontwrite(SYSFONT, 10, 10, sysmsg, EMPHNONE, cgreen);
  1700.     XFlush();
  1701.     }
  1702.  
  1703. charunshow(n)
  1704.     {
  1705.     fontwrite(SYSFONT, 10, 10, sysmsg, EMPHNONE, cblack);
  1706.     while (n--)
  1707.     {
  1708.     if (sysmsgloc) sysmsg[--sysmsgloc] = '\0';
  1709.     }
  1710.     fontwrite(SYSFONT, 10, 10, sysmsg, EMPHNONE, cgreen);
  1711.     XFlush();
  1712.     }
  1713.  
  1714. erase()
  1715.     {
  1716.     XPixSet(win, 0, 0, screenw, screenh, cblack);
  1717.     fontwrite(SYSFONT, 10, 10, sysmsg, EMPHNONE, cgreen);
  1718.     XFlush();
  1719.     }
  1720.  
  1721. /*
  1722.  * internal stuff
  1723.  */
  1724.  
  1725. findcolor(r, g, b)
  1726.     int r, g, b;
  1727.     {
  1728.     Color c;
  1729.     c.red = r*65535;
  1730.     c.green= g*65535;
  1731.     c.blue = b*65535;
  1732.     if (!XGetHardwareColor(&c))
  1733.     {
  1734. /*    err("no more room in color table"); */
  1735.     return(b*4+g*2+r);
  1736.     }
  1737.     return(c.pixel);
  1738.     }
  1739.  
  1740. mx(ev)
  1741.     XKeyEvent *ev;
  1742.     {
  1743.     return(ev->x);
  1744.     }
  1745.  
  1746. my(ev)
  1747.     XKeyEvent *ev;
  1748.     {
  1749.     return(screenh - ev->y + 1);
  1750.     }
  1751.  
  1752. writescan(x, y, pixels, outaddr, color)
  1753.     int x, y, pixels, *outaddr, color;
  1754.     {
  1755.     if (pixels <= 0) return;    /* PARANOIA: should not ever happen */
  1756.     if (!lut && color == cred)
  1757.     {
  1758.     register int i, lim;
  1759.     lim = (pixels+31)/32;
  1760.     if ((x^y) & 0x1) for(i=0; i<lim; i++) outaddr[i] &= 0x55555555;
  1761.     else for(i=0; i<lim; i++) outaddr[i] &= 0xaaaaaaaa;
  1762.     color = cwhite;
  1763.     }
  1764.     swapshorts(outaddr, (pixels+31)/8);
  1765.     XBitmapBitsPut(win, x, y, pixels, 1,
  1766.     outaddr, color, cblack, 0, GXcopy, AllPlanes);
  1767.     }
  1768.  
  1769. swapshorts(buf, len)
  1770.     register unsigned char *buf;
  1771.     {
  1772.     unsigned char c1, c2, c3, c4;
  1773.     register int count, i;
  1774.     if (!maptab[1]) maptabinit();
  1775.     count = len/4;
  1776.     for (i=0; i<count; i++)
  1777.     {
  1778.     c1 = *buf++;
  1779.     c2 = *buf++;
  1780.     c3 = *buf++;
  1781.     c4 = *buf;
  1782.     *buf-- = maptab[c1];
  1783.     *buf-- = maptab[c2];
  1784.     *buf-- = maptab[c3];
  1785.     *buf   = maptab[c4];
  1786.     buf += 4;
  1787.     }
  1788.     }
  1789.  
  1790. maptabinit()
  1791.     {
  1792.     register int i, j;
  1793.     unsigned char mask;
  1794.     for(i = 0; i<256; i++)
  1795.     {
  1796.     mask = 0;
  1797.     for(j = 0; j < 8; j++) if (i & (1<<j)) mask |= 1<<(7-j);
  1798.     maptab[i] = mask;
  1799.     }
  1800.     }
  1801. SHAR_EOF
  1802. #    End of shell archive
  1803. exit 0
  1804.  
  1805.  
  1806. -- 
  1807.  
  1808. Rich $alz            "Anger is an energy"
  1809. Cronus Project, BBN Labs    rsalz@bbn.com
  1810. Moderator, comp.sources.unix    sources@uunet.uu.net
  1811.